#ifndef CVBASEOBJECT_H_INCLUDED
#define CVBASEOBJECT_H_INCLUDED

//predecl
namespace cvObjects { class BaseObject; }

#include <vector>
#include <list>
#include <General/cvMemory.h>
typedef std::vector<cvObjects::BaseObject*, cvPoolAllocator<cvObjects::BaseObject*>::CON> baseobj_vector_t;
typedef std::list<cvObjects::BaseObject*, cvPoolAllocator<cvObjects::BaseObject*>::RAN> baseobj_list_t;

#include <Logger/GlobalLogger.h>
#include <Math/Bitfield.h>


/** Implemented attribute relativity flags.
    Ie. modes to parent diffent object together.
 */
enum
{
	/* BaseObject */
	OBJ_NOTHING		 	= 0x0,			// don't set anything, this flag can't be set by user.
	OBJ_ALL	 			= 0xFFFFFFFF,	// All possible object proberties are relative to parent.
	OBJ_DEFAULT 		= 0x80000000,	// Specific default for the object type. (only used in setParent)
	OBJ_DATA			= 0x00000001,	// is parent user data copied into children?
	/* EmptyObject */
	OBJ_X	 			= 0x00000002,	// is object x relative to parent?
	OBJ_Y	 			= 0x00000004,	// is object y relative to parent?
	OBJ_ROTATION		= 0x00000008,	// is object angle relative to parent?
	OBJ_XY	 			= 0x00000006,	// (compound flag) object is translated by parent position
	OBJ_XYROT	 		= 0x0000000E, 	// (compound flag)
	/* BaseCameraObject */
	OBJ_VIEWPORT_L		= 0x00000010,   // parent object's VIEWPORT_T and VIEWPORT_B are copied, and child's VIEWPORT_L is relative to parent's VIEWPORT_R.
	OBJ_VIEWPORT_R		= 0x00000020,   // parent object's VIEWPORT_T and VIEWPORT_B are copied, and child's VIEWPORT_R is relative to parent's VIEWPORT_L.
	OBJ_VIEWPORT_T		= 0x00000040,   // parent object's VIEWPORT_L and VIEWPORT_R are copied, and child's VIEWPORT_B is relative to parent's VIEWPORT_L.
	OBJ_VIEWPORT_B		= 0x00000080,   // parent object's VIEWPORT_L and VIEWPORT_R are copied, and child's VIEWPORT_T is relative to parent's VIEWPORT_L.
	OBJ_VIEWPORT_XY		= 0x00000030,	// child cameraobject's viewport position is relative to parent cameraobject's viewport position. (Like OBJ_XY)
	OBJ_VIEWPORT_WH		= 0x000000C0,	// child cameraobject's viewport size is relative to parent cameraobject's viewport size.
	OBJ_VIEWPORT_XYWH	= 0x000000F0,	// child viewport position and size is relative to parent.
	OBJ_ZOOM_X			= 0x00000100,   // child camera zoom's x-component is relative to parent's.
	OBJ_ZOOM_Y			= 0x00000200,   // child camera zoom's y-component is relative to parent's.
	OBJ_ZOOM_XY			= 0x00000300	// (compound flag)
};

namespace cvObjects
{
	/**
	 *	The BaseObject.
	 *	This object has no position nor rotation. It's an "pure state object".
	 */
	class BaseObject
	{
		public:

			/**
			 * Construct a BaseObject (named constructor idiom).
			 */
			static BaseObject * create();

			/** Creates an duplicate of the object. <flags> tell what attributes are 'cloned'
			 * from the orginal object. For example, copies may share the same texture or colour.
			 */
			virtual BaseObject * copy( cvMath::bitfield_t flags );

			/**
			 * Destroy
			 */
			virtual void destroy();
			static void purgeMemoryPool();

			/**
			 *	TYPE OF the object, See ObjectSubSystem.h */
			virtual int objectType() const;

			/// Object parentting and children.
			// Setups obj as parent of this and default relativity behaviour for object is turned on by default.
			// NOTE: Calls setRelativity( <flags> ).
			void setParent( BaseObject * obj, cvMath::bitfield_t flags = OBJ_DEFAULT );

			// Toggles spesific relativity behaviour on/off.
			// If parent does not have the flagged attrubute, the flag is ignored.
			virtual void setRelativity( cvMath::bitfield_t flags );

			BaseObject * getParent() const;
			size_t countChildren() const;
			BaseObject * getChild( size_t index ) const;

			/// Unparent object.
			// Cuts the object and its children out of the current parent-children-tree.
			// All children relativity settings are reset to nothing.
			void detach();
			// Cuts the object out of the parent-children-tree.
			// Children are moved to parent. (re-parented with object's parent with their old relativity settings.)
			// If <flags> parameter is given, children relativity behaviour is set consequently.
			// If object doesn't have a parent, all children relativity settings are reset to nothing.
			void detach_collapse( cvMath::bitfield_t flags = OBJ_DEFAULT );

			/** UPDATES the parent-children tree.*/
			virtual void update();

			/// SETTERS - If attribute is relative to parent the "local attribute" is set. (so it's impossible to modity the absolute)
			void setData( void * ptr );

			/// GETTERS
			void * getData();

			/// public std::list iterator that points to this.
			baseobj_list_t::iterator listItr;

		protected:
			BaseObject();
			~BaseObject();	// we do not need virtual destructor, beacuse virtual destroy() replaces it.

			/** Object type spesific updater.
			    updater()'s job is read attributes from parent object and possibly
			    do some calculation with this object and set non our local attrubutes.
			    */
			virtual void updater();



			/** Recursive tree update. Object MUST NOT call it on itself!
			    This method should only used in ObjectSubSystem::updateObjects() */
			void update_tree();
			/// Linearly recrussive update, needed in getters.
			void update_linear();

			/** Helper function searches over parentlist.
			    @Returns an object wich parent has all @flags attributes up-to-date.
			    Search goes though the whole list, so nearest object wich has no parent
			    is returned: we can't simplify this with recursion.
			    @parents != NULL, all objects iterated (including @return) are pushed into vector. */
			BaseObject * searchForRoot( cvMath::bitfield_t flags, baseobj_vector_t * parents );

			/// Parenting & object state.
			cvMath::bitfield_t m_relativityflags;	// what attributes are set relative to parent?
			cvMath::bitfield_t m_validrelatives; 	// dirty attribute flaging mechanism
			baseobj_vector_t m_child;


		private:
			/**
			 * MEMORY allocation
			 */
			// Hide new, delete, new[] and delete[], as objects shall never, ever be allocated/deleted in such ways.
			// Only way to create BaseObject is to call create() and to free is suicide with destroy()
			// Other object types shall follow this.

			void * operator new( size_t );				// prevent memory allocations outside of the pool, create() must be used no matter what.
			void operator delete( void* );				// prevent freeing on wrong pool, overide.
			void * operator new[]( size_t )	{ throw; }	// arrays are prohibited completly. they are EVIL.
			void operator delete[]( void* )	{ throw; }

			static cvPool pool;

			/// User dataptr
			void * m_dataptr;

			BaseObject * m_parent;

	};
};
#endif /* CVBASEOBJECT_H_INCLUDED */
